package com.autonavi.yunda.yunji.core.service.thirdpartyservice;

import com.autonavi.yunda.yunji.common.exception.AmapException;
import com.autonavi.yunda.yunji.common.exception.AmapExceptionCode;
import com.autonavi.yunda.yunji.common.exception.AmapPreconditions;
import com.autonavi.yunda.yunji.common.utils.JsonUtils;
import com.autonavi.yunda.yunji.common.utils.http.HttpClient;
import com.autonavi.yunda.yunji.common.utils.http.vo.HttpResponse;
import com.autonavi.yunda.yunji.core.enums.ParamSourceType;
import com.autonavi.yunda.yunji.core.model.dto.InterfaceConfigDTO;
import com.autonavi.yunda.yunji.core.model.dto.ProjectDTO;
import com.autonavi.yunda.yunji.core.model.vo.InterfaceData;
import com.autonavi.yunda.yunji.core.service.InterfaceConfigService;
import com.autonavi.yunda.yunji.core.service.ProjectService;
import com.autonavi.yunda.yunji.core.service.thirdpartyservice.vo.BaseHttpResponse;
import com.autonavi.yunda.yunji.core.service.thirdpartyservice.vo.FalconInterfaceApiVO;
import com.autonavi.yunda.yunji.core.vo.EngineData;
import com.autonavi.yunda.yunji.core.vo.response.FalconVO;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.groovy.util.Maps;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.autonavi.yunda.yunji.common.exception.AmapExceptionCode.FALCON_GET_ERROR;

/**
 * @author sunzhenbang
 * @date 2022/8/23 11:19 上午
 */
@Slf4j
@Component
public class FalconInterfaceService {
    private static final String CODE = "code";
    private static final String ZERO = "0";
    private static final String FALCON_HOST = "https://falcon-pre.amap.com";
    private static final String FALCON_TOKEN = "3e21ab62fb17400301d9f0156b6c3031";
    private static final String URI = "/api/v1/apis/";

    @Value("${yunji.engine.host}")
    private String apiServerHost;
    @Value("${falcon.groupId}")
    private String falconGroupId;
    @Resource
    InterfaceConfigService interfaceConfigService;
    @Resource
    ProjectService projectService;

    static HttpClient httpClient = new HttpClient();

    public void syncFalcon(Long id, String operator) {
        InterfaceConfigDTO dto = interfaceConfigService.findByIdOrThrow(id);
        ProjectDTO projectDTO = projectService.findByProjectIdOrThrow(dto.getProjectId());
        AmapPreconditions.checkArgumentForUser(StringUtils.isNotBlank(projectDTO.getFalconProjectId()), "该项目还未同步到falcon");
        try {
            InterfaceData interfaceData = dto.getInterfaceData();
            if (Strings.isBlank(interfaceData.falconId)) {
                interfaceData.falconId = createFalconApi(operator, projectDTO.getFalconProjectId(), dto.getName());
                interfaceConfigService.updateInterfaceData(dto.getId(), interfaceData);
            }
            updateFalconApiByFalconId(interfaceData.falconId, dto, operator);
        } catch (Exception e) {
            log.error("同步falcon异常", e);
            throw new AmapException(AmapExceptionCode.COMMON_REQUEST_ERROR, "接口同步falcon失败,请重试");
        }
    }

    private void updateFalconApiByFalconId(String falconId, InterfaceConfigDTO dto, String operator) {
        FalconInterfaceApiVO falconInterfaceApiVO = new FalconInterfaceApiVO();
        String title = "1".equals(dto.getVersion()) ? dto.getName() : dto.getName() + dto.getVersion();
        falconInterfaceApiVO.setOptions(Maps.of("description", dto.getDescription(), "method", List.of(dto.getMethod()), "title", title, "server", apiServerHost, "uri", dto.getUri()));
        falconInterfaceApiVO.setResponses(List.of(Maps.of("jsonString", JsonUtils.toString(dto.getInterfaceData().response))));
        EngineData engineData = new EngineData(dto.getEngineData());
        ArrayList<Object> params = new ArrayList<>();
        ArrayList<Object> headers = new ArrayList<>();
        ArrayList<Object> body = new ArrayList<>();
        engineData.fetchStartNode().inputParams.forEach(param -> {
            if (ParamSourceType.query.equals(param.source)) {
                params.add(Maps.of("name", param.name, "type", param.type, "description", param.desc, "required", param.require, "value", param.debugValue, "in", ParamSourceType.query, "string", ""));
            } else if (ParamSourceType.headers.equals(param.source)) {
                headers.add(Maps.of("name", param.name, "value", param.debugValue));
            } else if (ParamSourceType.body.equals(param.source)) {
                body.add(Maps.of("name", param.name, "type", param.type, "description", param.desc, "required", param.require, "value", param.debugValue, "in", ParamSourceType.body, "string", ""));
            }
        });
        falconInterfaceApiVO.setBody(Maps.of("content", body, "mode", "json"));
        falconInterfaceApiVO.setParameters(params);
        falconInterfaceApiVO.setHeaders(headers);
        HttpResponse httpResponse = httpClient.put(
                FALCON_HOST + "/api/v1/apis/" + falconId,
                JsonUtils.toString(Map.of("api", falconInterfaceApiVO)),
                Map.of("X-Falcon-Token", FALCON_TOKEN, "X-Falcon-Operator", operator),
                null
        );
        Map<String, Object> res = JsonUtils.from(httpResponse.getBody(), new TypeReference<>() {
        });
        if (res.isEmpty() || !ZERO.equals(res.get(CODE).toString())) {
            throw new AmapException(AmapExceptionCode.COMMON_ILLEGAL_PARAM, res.get("errmsg") == null ? "falcon更新接口失败" : res.get("errmsg").toString());
        }
    }

    private String createFalconApi(String operator, String projectId, String title) {
        HttpResponse httpResponse = httpClient.post(
                FALCON_HOST + URI,
                JsonUtils.toString(Map.of("project_id", projectId, "title", title)),
                Map.of("X-Falcon-Token", FALCON_TOKEN, "X-Falcon-Operator", operator),
                null
        );
        Map<String, Object> res = JsonUtils.from(httpResponse.getBody(), new TypeReference<>() {
        });
        if (!ZERO.equals(res.get(CODE).toString())) {
            throw new AmapException(AmapExceptionCode.COMMON_ILLEGAL_PARAM, "falcon创建接口失败");
        }
        Map<String, String> data = (Map<String, String>) res.get("data");
        return data.get("id");
    }


    public FalconVO getFalconById(String falconId, String operator) {
        HttpResponse httpResponse = httpClient.get(
                FALCON_HOST + URI + falconId,
                Map.of("X-Falcon-Token", FALCON_TOKEN, "X-Falcon-Operator", operator)
        );
        BaseHttpResponse<FalconVO> response = JsonUtils.from(httpResponse.getBody(), new TypeReference<>() {
        });
        FalconVO falconVO = response.getData(new TypeReference<>() {
        });
        log.info("获取falcon返回结果:{}", JsonUtils.toString(response));
        AmapPreconditions.checkArgument(Objects.nonNull(falconVO), FALCON_GET_ERROR,
                "获取falcon失败");
        return falconVO;
    }

    public String createFalconProject(String title, String description, String operator) {
        HttpResponse httpResponse = httpClient.post(
                FALCON_HOST + "/api/v1/projects/",
                JsonUtils.toString(Map.of("group_id", falconGroupId, "title", title, "description", description)),
                Map.of("X-Falcon-Token", FALCON_TOKEN, "X-Falcon-Operator", operator),
                null
        );
        log.info("createFalconProject response :{}", httpResponse.getBody());
        Map<String, Object> res = JsonUtils.from(httpResponse.getBody(), new TypeReference<>() {
        });
        if (!ZERO.equals(res.get(CODE).toString())) {
            throw new AmapException(AmapExceptionCode.COMMON_ILLEGAL_PARAM, "falcon项目创建失败");
        }
        Map<String, String> data = (Map<String, String>) res.get("data");
        String falconProjectId = data.get("id");
        AmapPreconditions.checkArgumentForUser(Strings.isNotBlank(falconProjectId), "falcon项目创建失败");
        return falconProjectId;
    }

}
